package com.example.tcpmaster;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;


import com.cz.basetool.ui_work.thread.ThreadManager;
import com.cz.basetool.ui_work.util.log.AndroidConsoleLogPrinter;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;

/**
 * Created by lianxiang on 2017/9/6.
 * Socket最底层的操作
 */
public abstract class AbsSocketTransceiver implements Runnable {
    private static final String TAG = "AbsSocketTransceiver";
    private Socket socket;
    private TcpClient tcpClient;
    private TcpSender sender;
    protected boolean runFlag;
    private DataInputStream in;
    private DataOutputStream out;

    private HandlerThread handlerThread;
    private Handler parseHandler;
    private OnSocketTransceiverStateListener onSocketTransceiverStateListener;

    private long taskTimeoutMilliSeconds = 5 * 1000;    //业务 等待超时时间


    private Timer mTimer;
    private TimerTask mTimerTask;
    private boolean isEffective;
    public boolean startTime = true;

    public AbsSocketTransceiver(TcpClient tcpClient, Socket socket) {
        this.tcpClient = tcpClient;
        this.socket = socket;
        this.sender = new TcpSender();
    }

    private Handler.Callback callback = new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            onHandleMessage(msg);
            return true;
        }
    };

    /**
     * 开启Socket收发
     * <p>
     * 如果开启失败，会断开连接并回调{@code onDisconnect()}
     */
    public void start() {
        //*********!!!!!利用Handler的轮循机制，缓存数据到队列中，保证回调有序的进行!!!!!!!!!!!!*************************
        handlerThread = new HandlerThread(TAG + "Handler");
        handlerThread.start();
        parseHandler = new Handler(handlerThread.getLooper(), callback);
        //*********!!!!!利用Handler的轮循机制，缓存数据到队列中，保证回调有序的进行!!!!!!!!!!!!*************************

        runFlag = true;
        new Thread(this, TAG).start();
    }

    @Override
    public void run() {
        try {
            in = new DataInputStream(this.socket.getInputStream());
            out = new DataOutputStream(this.socket.getOutputStream());
        } catch (IOException e) {
            if (onSocketTransceiverStateListener != null) {
                onSocketTransceiverStateListener.onException(new Exception(e.getMessage() + "flag$#R$$$#"));
            }

            e.printStackTrace();
            runFlag = false;
        }
        while (runFlag) {
            try {
                onRead(in);
            } catch (Exception e) {
                if (onSocketTransceiverStateListener != null) {
                    onSocketTransceiverStateListener.onException(new Exception(e.getMessage() + "连接被动断开"));
                }

                // 连接被断开(被动)
                e.printStackTrace();
                runFlag = false;
            }
        }
        // 断开连接
        stop();
        if (onSocketTransceiverStateListener != null) {
            onSocketTransceiverStateListener.onDisconnect();
        }
    }

    /**
     * 断开连接(主动)
     * <p>
     * 连接断开后，会回调{@code onDisconnect()}
     */
    public void stop() {
        runFlag = false;
        try {

            if (in != null)
                in.close();
            if (out != null)
                out.close();
            if (socket != null)
                socket.close();
            if (sender != null)
                sender = null;
//            socket.shutdownInput();
            in = null;
            out = null;
            socket = null;

            //关闭Handler轮循
            parseHandler.removeCallbacksAndMessages(null);
            parseHandler.getLooper().quit();
            handlerThread.quit();
            handlerThread.stop();
        } catch (Exception e) {
            e.printStackTrace();
            if (onSocketTransceiverStateListener != null) {
                onSocketTransceiverStateListener.onException(new Exception(e.getMessage() + "主动断开"));
            }

        }
    }

    /**
     * 发送字符串
     *
     * @param byteArr
     * @return
     */
    public boolean send(byte[] byteArr) {
        if (sender == null) {
            sender = new TcpSender();
        }
        sender.setData(byteArr);
        startTimer(taskTimeoutMilliSeconds);
        try {
            return (boolean) ThreadManager.getInstance().submitTaskWithoutException(sender).get();
        } catch (Exception e) {
            if (onSocketTransceiverStateListener != null) {
                onSocketTransceiverStateListener.onException(new Exception(e.getMessage() + "send---------------"));
            }
            e.printStackTrace();
        }
        return false;
    }

    public void startTimer(long overtime) {
        startTime = true;
        mTimer = new Timer();
        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                isEffective = false;
                if (startTime) {
                    onRequestTimeOut();
                }
                stopTimer();
            }
        };
        if (mTimer != null && mTimerTask != null) {
            mTimer.schedule(mTimerTask, overtime);
            AndroidConsoleLogPrinter.d("cz", "开始计算超时," + overtime + "毫秒之后");
        }
    }

    public void stopTimer() {
        if (mTimer != null) {
            mTimer.cancel();
            mTimer = null;
        }
        if (mTimerTask != null) {
            mTimerTask.cancel();
            mTimerTask = null;
        }
        isEffective = true;
    }


    /**
     * 读取数据
     *
     * @param in
     */
    public abstract void onRead(InputStream in) throws IOException;

    /**
     * 处理Handler的数据
     *
     * @param message
     * @return
     */
    public abstract boolean onHandleMessage(Message message);

    /**
     * 将服务器的数据发送到Handler
     *
     * @param message
     */
    protected void sendMessage(Message message) {
        parseHandler.sendMessage(message);
    }

    protected void sendMessage(int what, Object data) {
        parseHandler.obtainMessage(what, data).sendToTarget();
    }

    public interface OnSocketTransceiverStateListener {
        void onReceive(String data);

        void onDisconnect();

        void onException(Exception e);

        void onRequestTimeOut();
    }

    public void onRequestTimeOut() {
        onSocketTransceiverStateListener.onRequestTimeOut();
    }

    public void setOnSocketTransceiverStateListener(OnSocketTransceiverStateListener onSocketTransceiverStateListener) {
        this.onSocketTransceiverStateListener = onSocketTransceiverStateListener;
    }

    protected void onReceive(String data) {
        if (onSocketTransceiverStateListener != null) {
            onSocketTransceiverStateListener.onReceive(data);
        }
    }

    private class TcpSender implements Callable<Boolean> {

        private byte[] data;

        public void setData(byte[] data) {
            this.data = new byte[data.length];
            System.arraycopy(data, 0, this.data, 0, data.length);

        }

        @Override
        public Boolean call() throws Exception {
            if (out != null && data.length > 0) {
                try {
                    out.write(data);
                    out.flush();
                    return true;
                } catch (Exception e) {
                    e.printStackTrace();
                    if (onSocketTransceiverStateListener != null) {
                        onSocketTransceiverStateListener.onException(new Exception(e.getMessage() + "TcpSender call---------------"));
                    }
                }
            }
            return false;
        }
    }

}
